#ifndef PD_CORE_H_
#define PD_CORE_H_

#include "common.h"

/* Default retry count for transmitting */
/* Set to 0 <retry by FW> for TD.PD.LL.E2 Retransmission */
#define PD_RETRY_COUNT      3
#define PD30_RETRY_COUNT    2

#define PD_HEADER_ROLE(prole, drole) \
		(((drole) << 5) | ((prole) << 8))
#define PD_HEADER_COMMON(msg_type, rev, id, cnt, ext, private) \
		((msg_type) | (rev << 6) | \
		 ((id) << 9) | ((cnt) << 12) | ((ext) << 15) | (private))
#define PD_HEADER_SOP(msg_type, rev, prole, drole, id, cnt, ext) \
		((msg_type) | (rev << 6) | \
		 ((drole) << 5) | ((prole) << 8) | \
		 ((id) << 9) | ((cnt) << 12) | ((ext) << 15))
#define PD_HEADER_SOP_PRIME(msg_type, rev, cable_plug, id, cnt, ext) \
        ((msg_type) | (rev << 6) | \
        ((cable_plug) << 8) | \
        ((id) << 9) | ((cnt) << 12) | ((ext) << 15))

#define PD_EXT_HEADER_PAYLOAD_INDEX	2

#define PD_EXT_HEADER_CHUNKED(header)	(((header) >> 15) & 1)
#define PD_EXT_HEADER_CHUNK_NR(header)	(((header) >> 11) & 0xF)
#define PD_EXT_HEADER_REQUEST(header)	(((header) >> 10) & 1)
#define PD_EXT_HEADER_DATA_SIZE(header)	(((header) >> 0) & 0x1FF)

#define PD_EXT_HEADER_CK(data_size, req, chunk_nr, chunked)	\
                ((data_size) | (req << 10) | \
                 ((chunk_nr) << 11) | (chunked << 15))

/* PDO : Power Data Object */
/*
 * 1. The vSafe5V Fixed Supply Object shall always be the first object.
 * 2. The remaining Fixed Supply Objects,
 *    if present, shall be sent in voltage order; lowest to highest.
 * 3. The Battery Supply Objects,
 *    if present shall be sent in Minimum Voltage order; lowest to highest.
 * 4. The Variable Supply (non battery) Objects,
 *    if present, shall be sent in Minimum Voltage order; lowest to highest.
 */
#define PDO_TYPE_FIXED		((uint32_t)0 << 30)
#define PDO_TYPE_BATTERY	((uint32_t)1 << 30)
#define PDO_TYPE_VARIABLE	((uint32_t)2 << 30)
#define PDO_TYPE_APDO		((uint32_t)3 << 30)
#define PDO_TYPE_MASK		((uint32_t)3 << 30)
#define PDO_TYPE_APDO_SPR_PPS   ((uint32_t)0 << 28)
#define PDO_TYPE_APDO_SPR_AVS   ((uint32_t)2 << 28)
#define PDO_TYPE_APDO_EPR_AVS   ((uint32_t)1 << 28)
#define PDO_TYPE(raw)		(raw & PDO_TYPE_MASK)
#define PDO_TYPE_VAL(raw)	(PDO_TYPE(raw) >> 30)

#define PDO_FIXED_DUAL_ROLE	((uint32_t)1 << 29) /* Dual role device */
#define PDO_FIXED_SUSPEND	((uint32_t)1 << 28) /* USB Suspend supported (SRC) */
#define PDO_FIXED_HIGH_CAP	((uint32_t)1 << 28) /* Higher Capability (SNK) */
#define PDO_FIXED_EXTERNAL	((uint32_t)1 << 27) /* Externally powered */
#define PDO_FIXED_COMM_CAP	((uint32_t)1 << 26) /* USB Communications Capable */
#define PDO_FIXED_DATA_SWAP	((uint32_t)1 << 25) /* Data role swap command supported */
#define PDO_FIXED_PEAK_CURR(i) ((i & 0x03) << 20) /* [21..20] Peak current */
#define PDO_FIXED_VOLT(mv) (((mv) & 0x3ff) << 10) /* Voltage in 50mV units */
#define PDO_FIXED_CURR(ma) (((ma) & 0x3ff) << 0)  /* Max current in 10mA units */
#define PDO_FIXED_EXTRACT_VOLT_RAW(raw)	(((raw) >> 10) & 0x3ff)
#define PDO_FIXED_EXTRACT_CURR_RAW(raw)	(((raw) >> 0) & 0x3ff)
#define PDO_FIXED_EXTRACT_VOLT(raw)	(PDO_FIXED_EXTRACT_VOLT_RAW(raw) * 50)
#define PDO_FIXED_EXTRACT_CURR(raw)	(PDO_FIXED_EXTRACT_CURR_RAW(raw) * 10)
#define PDO_FIXED_RESET_CURR(raw, ma)	((raw & ~0x3ff) | PDO_FIXED_CURR(ma))
#define PDO_FIXED(mv, ma, peak, flags) \
                 (PDO_FIXED_VOLT(mv) |\
                  PDO_FIXED_CURR(ma) | \
                  PDO_FIXED_PEAK_CURR(peak) | \
                  (flags))

#define PDO_VAR_MAX_VOLT(mv) ((((mv) / 50) & 0x3FF) << 20)
#define PDO_VAR_MIN_VOLT(mv) ((((mv) / 50) & 0x3FF) << 10)
#define PDO_VAR_OP_CURR(ma)  ((((ma) / 10) & 0x3FF) << 0)
#define PDO_VAR_EXTRACT_MAX_VOLT_RAW(raw)	(((raw) >> 20) & 0x3ff)
#define PDO_VAR_EXTRACT_MIN_VOLT_RAW(raw)	(((raw) >> 10) & 0x3ff)
#define PDO_VAR_EXTRACT_CURR_RAW(raw)		(((raw) >> 0) & 0x3ff)
#define PDO_VAR_EXTRACT_MAX_VOLT(raw)	(PDO_VAR_EXTRACT_MAX_VOLT_RAW(raw) * 50)
#define PDO_VAR_EXTRACT_MIN_VOLT(raw)	(PDO_VAR_EXTRACT_MIN_VOLT_RAW(raw) * 50)
#define PDO_VAR_EXTRACT_CURR(raw)	(PDO_VAR_EXTRACT_CURR_RAW(raw) * 10)
#define PDO_VAR_RESET_CURR(raw, ma)	((raw & ~0x3ff) | PDO_VAR_OP_CURR(ma))
#define PDO_VAR(min_mv, max_mv, op_ma) \
               (PDO_VAR_MIN_VOLT(min_mv) | \
                PDO_VAR_MAX_VOLT(max_mv) | \
                PDO_VAR_OP_CURR(op_ma)   | \
                PDO_TYPE_VARIABLE)

#define PDO_BATT_MAX_VOLT(mv) ((((mv) / 50) & 0x3FF) << 20)
#define PDO_BATT_MIN_VOLT(mv) ((((mv) / 50) & 0x3FF) << 10)
#define PDO_BATT_OP_POWER(mw) ((((mw) / 250) & 0x3FF) << 0)
#define PDO_BATT_EXTRACT_MAX_VOLT_RAW(raw)	(((raw) >> 20) & 0x3ff)
#define PDO_BATT_EXTRACT_MIN_VOLT_RAW(raw)	(((raw) >> 10) & 0x3ff)
#define PDO_BATT_EXTRACT_OP_POWER_RAW(raw)	(((raw) >> 0) & 0x3ff)
#define PDO_BATT_EXTRACT_MAX_VOLT(raw)	(PDO_BATT_EXTRACT_MAX_VOLT_RAW(raw) * 50)
#define PDO_BATT_EXTRACT_MIN_VOLT(raw)	(PDO_BATT_EXTRACT_MIN_VOLT_RAW(raw) * 50)
#define PDO_BATT_EXTRACT_OP_POWER(raw)	(PDO_BATT_EXTRACT_OP_POWER_RAW(raw) * 250)
#define PDO_BATT(min_mv, max_mv, op_mw) \
                (PDO_BATT_MIN_VOLT(min_mv) | \
                 PDO_BATT_MAX_VOLT(max_mv) | \
                 PDO_BATT_OP_POWER(op_mw) | \
                 PDO_TYPE_BATTERY)

#define APDO_TYPE_MASK              (3 << 28)
#define APDO_TYPE_PPS               (0 << 28)
#define APDO_TYPE(raw)              (raw & APDO_TYPE_MASK)
#define APDO_TYPE_VAL(raw)          (APDO_TYPE(raw) >> 28)

#define APDO_PPS_CURR_FOLDBACK      (1<<26)
#define APDO_PPS_MAX_VOLT(mv)       (((mv) & 0xff) << 17)
#define APDO_PPS_MIN_VOLT(mv)       (((mv) & 0xff) << 8)
#define APDO_PPS_CURR(ma)           (((ma) & 0x7f) << 0)
#define APDO_PPS_EXTRACT_MAX_VOLT_RAW(raw)      ((((raw) >> 17) & 0xff) * 100)
#define APDO_PPS_EXTRACT_MIN_VOLT_RAW(raw)      ((((raw) >> 8) & 0xff) * 100)
#define APDO_PPS_EXTRACT_CURR_RAW(raw)          ((((raw) >> 0) & 0x7f) * 50)
//#define APDO_PPS_EXTRACT_PWR_LIMIT(raw)         ((raw >> 27) & 0x1)
#define APDO_PPS(min_mv, max_mv, max_ma) \
                                    (APDO_PPS_MAX_VOLT(min_mv) | \
                                     APDO_PPS_MIN_VOLT(max_mv) | \
                                     APDO_PPS_CURR(max_ma) | \
                                     PDO_TYPE_APDO | \
                                     APDO_TYPE_PPS)

/*
 * VDO : Vendor Defined Message Object
 * VDM object is minimum of VDM header + 6 additional data objects.
 */

/*
 * VDM header
 * ----------
 * <31:16>  :: SVID
 * <15>     :: VDM type ( 1b == structured, 0b == unstructured )
 * <14:13>  :: Structured VDM version (can only be 00 == 1.0 currently)
 * <12:11>  :: reserved
 * <10:8>   :: object position (1-7 valid ... used for enter/exit mode only)
 * <7:6>    :: command type (SVDM only?)
 * <5>      :: reserved
 * <4:0>    :: command
 */

#define VDO(vid, type, custom)				\
	(((vid) << 16) |				\
	 ((type) << 15) |				\
	 ((custom) & 0x7FFF))

#define VDO_S(svid, ver, ver_min, cmd_type, cmd, obj)	\
	VDO(svid, 1, VDO_SVDM_VER(ver) | VDO_SVDM_VER_MIN(ver_min) | \
		VDO_CMDT(cmd_type) | VDO_OPOS(obj) | cmd)

#define VDO_REPLY(ver, ver_min, cmd_type, request_vdo)	\
	(VDO_SVDM_VER(ver) | VDO_SVDM_VER_MIN(ver_min) | VDO_CMDT(cmd_type) \
	| ((request_vdo) & (~0x78E0)))

#define SVDM_REV10	0
#define SVDM_REV20	1

#define VDO_SVDM_TYPE		(1 << 15)
#define VDO_SVDM_VER(x)		(x << 13)
#define VDO_SVDM_VER_MIN(x)	(x << 11)
#define VDO_OPOS(x)		(x << 8)
#define VDO_CMDT(x)		(x << 6)

#define PD_MSG_ID_MAX	8
#define CMDT_INIT     0
#define CMDT_RSP_ACK  1
#define CMDT_RSP_NAK  2
#define CMDT_RSP_BUSY 3

#define CMD_DISCOVER_IDENT  1
#define CMD_DISCOVER_SVIDS  2
#define CMD_DISCOVER_MODES  3
#define CMD_ENTER_MODE      4
#define CMD_EXIT_MODE       5
#define CMD_ATTENTION       6
#define CMD_DP_STATUS      16
#define CMD_DP_CONFIG      17

#define PD_VDO_VID(vdo)  ((vdo) >> 16)
#define PD_VDO_SVDM(vdo) (((vdo) >> 15) & 1)
#define PD_VDO_OPOS(vdo) (((vdo) >> 8) & 0x7)
#define PD_VDO_VER_MIN(vdo) (((vdo) >> 11) & 0x3)
#define PD_VDO_CMD(vdo)  ((vdo) & 0x1f)
#define PD_VDO_CMDT(vdo) (((vdo) >> 6) & 0x3)


/*
 * Cable VDO
 * ---------
 * <31:28> :: Cable HW version
 * <27:24> :: Cable FW version
 * <23:20> :: SBZ
 * <19:18> :: type-C to Type-A/B/C (00b == A, 01 == B, 10 == C)
 * <17>    :: Type-C to Plug/Receptacle (0b == plug, 1b == receptacle)
 * <16:13> :: cable latency (0001 == <10ns(~1m length))
 * <12:11> :: cable termination type (11b == both ends active VCONN req)
 * <10>    :: SSTX1 Directionality support (0b == fixed, 1b == cfgable)
 * <9>     :: SSTX2 Directionality support
 * <8>     :: SSRX1 Directionality support
 * <7>     :: SSRX2 Directionality support
 * <6:5>   :: Vbus current handling capability
 * <4>     :: Vbus through cable (0b == no, 1b == yes)
 * <3>     :: SOP" controller present? (0b == no, 1b == yes)
 * <2:0>   :: USB SS Signaling support
 */
#define CABLE_ATYPE 0
#define CABLE_BTYPE 1
#define CABLE_CTYPE 2
#define CABLE_PLUG       0
#define CABLE_RECEPTACLE 1
#define CABLE_CURR_3A    1
#define CABLE_CURR_5A    2
#define CABLE_USBSS_U2_ONLY	0
#define CABLE_USBSS_U32_GEN1	1
#define CABLE_USBSS_U32_GEN2	2
#define CABLE_USBSS_U4_GEN3	3
#define CABLE_USBSS_U4_GEN4	4
#define VDO_CABLE(hw, fw, cbl, gdr, lat, term, tx1d,\
			tx2d, rx1d, rx2d, cur, vps, sopp, usbss) \
	(((hw) & 0x7) << 28 | ((fw) & 0x7) << 24 | ((cbl) & 0x3) << 18	\
	 | (gdr) << 17 | ((lat) & 0x7) << 13 | ((term) & 0x3) << 11	\
	 | (tx1d) << 10 | (tx2d) << 9 | (rx1d) << 8 | (rx2d) << 7	\
	 | ((cur) & 0x3) << 5 | (vps) << 4 | (sopp) << 3		\
	 | ((usbss) & 0x7))

#define PD_VDO_CABLE_CURR(x)		(((x) >> 5) & 0x03)
#define PD_VDO_CABLE_USB_SIGNAL(x)	((x) & 0x07)

/*
 * SVDM Discover SVIDs request -> response
 *
 * Request is properly formatted VDM Header with discover SVIDs command.
 * Response is a set of SVIDs of all supported SVIDs with all zero's to
 * mark the end of SVIDs.  If more than 12 SVIDs are supported command SHOULD be
 * repeated.
 */
#define VDO_SVID(svid0, svid1) (((svid0) & 0xffff) << 16 | ((svid1) & 0xffff))
#define PD_VDO_SVID_SVID0(vdo) ((vdo) >> 16)
#define PD_VDO_SVID_SVID1(vdo) ((vdo) & 0xffff)



/*
 * DisplayPort modes capabilities
 * -------------------------------
 * <31:30> : VDO Version
 * <29:24> : SBZ
 * <23:16> : UFP_D pin assignment supported
 * <15:8>  : DFP_D pin assignment supported
 * <7>     : USB 2.0 signaling (0b=yes, 1b=no)
 * <6>     : Plug | Receptacle (0b == plug, 1b == receptacle)
 * <5:2>   : xxx1: Supports DPv1.3, xx1x Supports USB Gen 2 signaling
 *           Other bits are reserved.
 * <1:0>   : Port Capability (00b=rsv, 01b=sink, 10b=src 11b=both)
 */
#define VDO_MODE_DP(snkp, srcp, usb2, gdr, sig, cap)			\
	(((snkp) & 0xff) << 16 | ((srcp) & 0xff) << 8 | ((usb2) & 1) << 7 |\
	 ((gdr) & 1) << 6 | ((sig) & 0xf) << 2 | ((cap) & 0x3))

#define MODE_DP_PIN_C			0x04
#define MODE_DP_PIN_D			0x08
#define MODE_DP_PIN_E			0x10

#define MODE_DP_SNK			0x1
#define MODE_DP_SRC			0x2
#define MODE_DP_BOTH			0x3

#define MODE_DP_PORT_CAP(mode)		(mode & 0x03)
#define MODE_DP_SIGNAL_SUPPORT(mode)	((mode >> 2) & 0x0f)
#define MODE_DP_RECEPT(mode)		((mode >> 6) & 0x01)

#define MODE_DP_PIN_DFP(mode)		((mode >> 8) & 0xff)
#define MODE_DP_PIN_UFP(mode)		((mode >> 16) & 0xff)

#define PD_DP_DFP_D_PIN_CAPS(x)	(MODE_DP_RECEPT(x) ? \
		MODE_DP_PIN_DFP(x) : MODE_DP_PIN_UFP(x))

#define PD_DP_UFP_D_PIN_CAPS(x)	(MODE_DP_RECEPT(x) ? \
		MODE_DP_PIN_UFP(x) : MODE_DP_PIN_DFP(x))

#define MODE_DP_UHBR13_5(mode)		((mode >> 26) & 0x01)

#define MODE_DP_ACTIVE_COMPONENT(mode)	((mode >> 28) & 0x03)

#define MODE_DP_VDO_VERSION(mode)	((mode >> 30) & 0x03)

#define MODE_DP_VDO_VERSION_SHFT	30
#define MODE_DP_VDO_VERSION_MASK	(3 << MODE_DP_VDO_VERSION_SHFT)


/*
 * DisplayPort Status VDO
 * ----------------------
 * <31:9> : SBZ
 * <8>    : IRQ_HPD : 1 == irq arrived since last message otherwise 0.
 * <7>    : HPD state : 0 = HPD_LOW, 1 == HPD_HIGH
 * <6>    : Exit DP Alt mode: 0 == maintain, 1 == exit
 * <5>    : USB config : 0 == maintain current, 1 == switch to USB from DP
 * <4>    : Multi-function preference : 0 == no pref, 1 == MF preferred.
 * <3>    : enabled : is DPout on/off.
 * <2>    : power low : 0 == normal or LPM disabled, 1 == DP disabled for LPM
 * <1:0>  : connect status : 00b ==  no (DFP|UFP)_D is connected or disabled.
 *          01b == DFP_D connected, 10b == UFP_D connected, 11b == both.
 */

#define VDO_DP_STATUS(irq, lvl, amode, usbc, mf, en, lp, conn)		\
	(((irq) & 1) << 8 | ((lvl) & 1) << 7 | ((amode) & 1) << 6	\
	 | ((usbc) & 1) << 5 | ((mf) & 1) << 4 | ((en) & 1) << 3	\
	 | ((lp) & 1) << 2 | ((conn & 0x3) << 0))

#define PD_VDO_DPSTS_IRQ_HPD(x) (((x) >> 8) & 1)
#define PD_VDO_DPSTS_HPD_STATE(x) (((x) >> 7) & 1)
#define PD_VDO_DPSTS_MF_PREF(x) (((x) >> 4) & 1)

#define PD_VDO_DPSTS_CONNECT(x)	(((x) >> 0) & 0x03)

#define DPSTS_DISCONNECT		0

#define DPSTS_DFP_D_CONNECTED	(1 << 0)
#define DPSTS_UFP_D_CONNECTED	(1 << 1)
#define DPSTS_BOTH_CONNECTED	(DPSTS_DFP_D_CONNECTED | DPSTS_UFP_D_CONNECTED)

/* UFP_U only */
#define DPSTS_DP_ENABLED		(1<<3)
#define DPSTS_DP_MF_PREF		(1<<4)
#define DPSTS_DP_USB_CONFIG		(1<<5)
#define DPSTS_DP_EXIT_ALT_MODE		(1<<6)

/* UFP_D only */
#define DPSTS_DP_HPD_STATUS		(1<<7)
#define DPSTS_DP_HPD_IRQ		(1<<8)

/* Per DisplayPort Spec v1.3 Section 3.3 */
#define HPD_USTREAM_DEBOUNCE_LVL (2*MSEC)
#define HPD_USTREAM_DEBOUNCE_IRQ (250)
#define HPD_DSTREAM_DEBOUNCE_IRQ (750)  /* between 500-1000us */

/*
 * DisplayPort Configure VDO
 * -------------------------
 * <31:24> : SBZ
 * <23:16> : SBZ
 * <15:8>  : Pin assignment requested.  Choose one from mode caps.
 * <7:6>   : SBZ
 * <5:2>   : signalling : 1h == DP v1.3, 2h == Gen 2
 *           Oh is only for USB, remaining values are reserved
 * <1:0>   : cfg : 00 == USB, 01 == DFP_D, 10 == UFP_D, 11 == reserved
 */

#define DP_CONFIG_USB			0
#define DP_CONFIG_DFP_D			1
#define DP_CONFIG_UFP_D			2

#define DP_CONFIG_AC_PASSIVE		0
#define DP_CONFIG_AC_ACTIVE_RETIMER	1
#define DP_CONFIG_AC_ACTIVE_REDRIVER	2
#define DP_CONFIG_AC_OPTICAL		3

#define VDO_DP_CFG(ac, uhbr13_5, pin, sig, cfg)	\
	((ac) << 28 | (uhbr13_5) << 26 | ((pin) & 0xff) << 8 |\
	 ((cfg) ? ((sig) & 0xf) << 2 : 0) | (cfg) & 0x3)

#define PD_DP_CFG_ROLE(x)		(x & 0x3)
#define PD_DP_CFG_DFP_D(x)		(PD_DP_CFG_ROLE(x) == DP_CONFIG_DFP_D)

#define DP_SIG_HBR3			(0x01)
#define DP_SIG_UHBR10			(0x02)
#define DP_SIG_UHBR20			(0x04)
#define DP_CFG_SIGNAL(x)		(((x) >> 2) & 0xf)

#define DP_PIN_ASSIGN_SUPPORT_C		(1 << 2)
#define DP_PIN_ASSIGN_SUPPORT_D		(1 << 3)
#define DP_PIN_ASSIGN_SUPPORT_E		(1 << 4)


/*
 * SVDM Identity request -> response
 *
 * Request is simply properly formatted SVDM header
 *
 * Response is 4 data objects:
 * [0] :: SVDM header
 * [1] :: Identitiy header
 * [2] :: Cert Stat VDO
 * [3] :: Product VDO
 * [4] :: Cable VDO
 *
 */

/*
 * SVDM Identity Header
 * --------------------
 * <31>     :: data capable as a USB host
 * <30>     :: data capable as a USB device
 * <29:27>  :: product type for UFP/Cable
 * <26>     :: modal operation supported (1b == yes)
 * <25:23>  :: product type for DFP
 * <22:16>  :: SBZ
 * <15:0>   :: USB-IF assigned VID for this cable vendor
 */

#define IDH_PTYPE_UNDEF  0
#define IDH_PTYPE_HUB    1
#define IDH_PTYPE_PERIPH 2
#define IDH_PTYPE_PCABLE 3
#define IDH_PTYPE_ACABLE 4
#define IDH_PTYPE_AMA    5

#define IDH_PTYPE_DFP_UNDEF 0
#define IDH_PTYPE_DFP_HUB 1
#define IDH_PTYPE_DFP_HOST 2
#define IDH_PTYPE_DFP_PB 3
#define IDH_PTYPE_DFP_AMC 4


#define VDO_IDH(usbh, usbd, ptype, is_modal, ptype_dfp, ctype, vid) \
    ((usbh) << 31 | (usbd) << 30 \
    | ((ptype) & 0x7) << 27 \
    | (is_modal) << 26 \
    | ((ptype_dfp) & 0x7) << 23 \
    | ((ctype) & 0x3) << 21 \
    | ((vid) & 0xffff))

#define VDO_IDH_PD20(idh)	(idh & (~(0x1f << 21)))

#define PD_IDH_PTYPE(vdo)       (((vdo) >> 27) & 0x7)
#define PD_IDH_PTYPE_DFP(vdo)   (((vdo) >> 23) & 0x7)
#define PD_IDH_VID(vdo)         ((vdo) & 0xffff)
#define PD_IDH_VID_MASK         (0xffff)
#define PD_IDH_MODAL_SUPPORT    (1<<26)


#define VDO_PRODUCT(pid, bcd) (((pid) & 0xffff) << 16 | ((bcd) & 0xffff))
#define PD_PRODUCT_BCD(vdo) ((vdo) & 0xffff)
#define PD_PRODUCT_PID(vdo) (((vdo) >> 16) & 0xffff)

#define VDO_DFP(ver, hcap, port) (((ver) & 0x7) << 29 | ((hcap) & 0x7) << 24 | (port) & 0x1f)

/* BDO : BIST Data Object */
#define BDO_MODE_RECV       (0 << 28)
#define BDO_MODE_TRANSMIT   (1 << 28)
#define BDO_MODE_COUNTERS   (2 << 28)
#define BDO_MODE_CARRIER0   (3 << 28)
#define BDO_MODE_CARRIER1   (4 << 28)
#define BDO_MODE_CARRIER2   (5 << 28)
#define BDO_MODE_CARRIER3   (6 << 28)
#define BDO_MODE_EYE        (7 << 28)
#define BDO_MODE_TEST_DATA	((unsigned int)8 << 28)

#define BDO_MODE(obj)		(uint32_t)(obj & ((uint32_t)0xf << 28))
#define BDO(mode, cnt)      ((mode) | ((cnt) & 0xFFFF))

/* Power role */
#define PD_ROLE_SINK   0
#define PD_ROLE_SOURCE 1

/* Data role */
#define PD_ROLE_UFP    0
#define PD_ROLE_DFP    1

/* Vconn role */
#define PD_ROLE_VCONN_OFF 0
#define PD_ROLE_VCONN_ON  1
#define PD_ROLE_VCONN_DYNAMIC_OFF		2
#define PD_ROLE_VCONN_DYNAMIC_ON		3

#define PD_HEADER_EXT(header) (((header) >> 15) & 1)	/* pd30 */
#define PD_HEADER_REV(header)  (((header) >> 6) & 3)
#define PD_HEADER_CNT(header)  (((header) >> 12) & 7)
#define PD_HEADER_TYPE(header) ((header) & 0x1F)
#define PD_HEADER_ID(header)   (((header) >> 9) & 7)
#define PD_HEADER_PR(header)	(((header) >> 8) & 1)
#define PD_HEADER_DR(header)	(((header) >> 5) & 1)

#define PD30_SINK_TX_OK		TYPEC_CC_RP_3_0
#define PD30_SINK_TX_NG		TYPEC_CC_RP_1_5

/*
 * Get the pin assignment mask
 * for backward compatibility, if it is null,
 * get the former sink pin assignment we used to be in <23:16>.
 */

#define DP_CFG_PIN(x)		(((x) >> 8) & 0xff ?\
				((x) >> 8) & 0xff : ((x) >> 16) & 0xff)
#define DP_CFG_VDO_VERSION_SHFT	30
/* USB-IF SVIDs */
#define USB_SID_PD		0xff00	/* power delivery */
#define USB_SID_DISPLAYPORT	0xff01	/* display port */
#define USB_SID_TBT		0x8087	/* Thunderbolt */
#define USB_VID_MQP		0x1748

/* new definitions*/

#define PD_RX_CAP_PE_IDLE				(0)
#define PD_RX_CAP_PE_DISABLE			(TCPC_RX_CAP_HARD_RESET)
#define PD_RX_CAP_PE_STARTUP			(TCPC_RX_CAP_HARD_RESET)
#define PD_RX_CAP_PE_HARDRESET			(0)
#define PD_RX_CAP_PE_SWAP	\
	(TCPC_RX_CAP_HARD_RESET|TCPC_RX_CAP_SOP)
#define PD_RX_CAP_PE_SEND_WAIT_CAP	\
	(TCPC_RX_CAP_HARD_RESET|TCPC_RX_CAP_SOP)
#define PD_RX_CAP_PE_DISCOVER_CABLE	\
	(TCPC_RX_CAP_HARD_RESET|TCPC_RX_CAP_SOP_PRIME)
#define PD_RX_CAP_PE_READY_UFP	\
	(TCPC_RX_CAP_HARD_RESET|TCPC_RX_CAP_SOP)

#if CONFIG_PD_DISCOVER_CABLE_ID
#define PD_RX_CAP_PE_READY_DFP	\
	(TCPC_RX_CAP_HARD_RESET|TCPC_RX_CAP_SOP|TCPC_RX_CAP_SOP_PRIME)
#else
#define PD_RX_CAP_PE_READY_DFP	(TCPC_RX_CAP_HARD_RESET|TCPC_RX_CAP_SOP)
#endif

/* RDO : Request Data Object */
#define RDO_OBJ_POS(n)             (((n) & 0xF) << 28)
#define RDO_POS(rdo)               (((rdo) >> 28) & 0xF)
#define RDO_GIVE_BACK              (1 << 27)
#define RDO_CAP_MISMATCH           (1 << 26)
#define RDO_COMM_CAP               (1 << 25)
#define RDO_NO_SUSPEND             (1 << 24)
#define RDO_EXTEND_MESSAGE	(1 << 23)
#define RDO_CURR_FOLDBACK	(1 << 22)

#define RDO_FIXED_VAR_OP_CURR(ma)  ((((ma) / 10) & 0x3FF) << 10)
#define RDO_FIXED_VAR_MAX_CURR(ma) ((((ma) / 10) & 0x3FF) << 0)

#define RDO_FIXED_VAR_EXTRACT_OP_CURR(raw)	(((raw >> 10 & 0x3ff)) * 10)
#define RDO_FIXED_VAR_EXTRACT_MAX_CURR(raw)	(((raw >> 0 & 0x3ff)) * 10)

#define RDO_BATT_OP_POWER(mw)      ((((mw) / 250) & 0x3FF) << 10)
#define RDO_BATT_MAX_POWER(mw)     ((((mw) / 250) & 0x3FF) << 0)

#define RDO_BATT_EXTRACT_OP_POWER(raw)	(((raw >> 10 & 0x3ff)) * 250)
#define RDO_BATT_EXTRACT_MAX_POWER(raw)	(((raw >> 0 & 0x3ff)) * 250)

#define RDO_APDO_OP_MV(mv)	((((mv) / 20) & 0xFFF) << 9)
#define RDO_APDO_OP_MA(ma)	((((ma) / 50) & 0x7F) << 0)

#define RDO_APDO_EXTRACT_OP_MV(raw)	(((raw >> 9 & 0xFFF)) * 20)
#define RDO_APDO_EXTRACT_OP_MA(raw)	(((raw >> 0 & 0x7F)) * 50)

#define RDO_FIXED(n, op_ma, max_ma, flags) \
				(RDO_OBJ_POS(n) | (flags) | \
				RDO_FIXED_VAR_OP_CURR(op_ma) | \
				RDO_FIXED_VAR_MAX_CURR(max_ma))

#define RDO_BATT(n, op_mw, max_mw, flags) \
				(RDO_OBJ_POS(n) | (flags) | \
				RDO_BATT_OP_POWER(op_mw) | \
				RDO_BATT_MAX_POWER(max_mw))

#define RDO_APDO(n, op_mv, op_ma, flags)	\
				(RDO_OBJ_POS(n) | (flags) | \
				RDO_APDO_OP_MV(op_mv) | \
				RDO_APDO_OP_MA(op_ma))

/* PD counter definitions */
#define PD_MESSAGE_ID_COUNT	7
#define PD_HARD_RESET_COUNT	2
#define PD_CAPS_COUNT			50
#define PD_WAIT_RETRY_COUNT		1
#define PD_DISCOVER_ID_COUNT	3	/* max : 20 */
#define PD_DISCOVER_ID30_COUNT	2	/* max : 20 */
#define PD_RESPONSE_ID30_COUNT	3
/* Protocol revision */
#define PD_REV10	0
#define PD_REV20	1
#define PD_REV30	2

#define MAX_EXTENDED_MSG_CHUNK_LEN	26
#define MAX_EXTENDED_MSG_LEGACY_LEN	26

#define PD_EXT_HEADER_CHUNKED(header)	(((header) >> 15) & 1)
#define PD_EXT_HEADER_CHUNK_NR(header)	(((header) >> 11) & 0xF)
#define PD_EXT_HEADER_REQUEST(header)	(((header) >> 10) & 1)
#define PD_EXT_HEADER_DATA_SIZE(header)	(((header) >> 0) & 0x1FF)

enum {
	PD_BIST_MODE_DISABLE = 0,
	PD_BIST_MODE_EVENT_PENDING,
	PD_BIST_MODE_TEST_DATA,
};

enum {	/* pd_traffic_control */
	PD_SINK_TX_OK = 0,
	PD_SINK_TX_NG = 1,
	PD_SOURCE_TX_OK = 2,
	PD_SOURCE_TX_START = 3,
	PD_SINK_TX_START = 4,
};

enum {
	PD_WAIT_VBUS_DISABLE = 0,
	PD_WAIT_VBUS_VALID_ONCE = 1,
	PD_WAIT_VBUS_INVALID_ONCE = 2,
	PD_WAIT_VBUS_SAFE0V_ONCE = 3,
	PD_WAIT_VBUS_STABLE_ONCE = 4,
};

enum {
    CABLE_DISCOVERED_NONE = 0,
    CABLE_DISCOVERED_ID,
    CABLE_DISCOVERED_SVIDS,
    CABLE_DISCOVERED_MODES,
};

bool pd_put_dpm_notify_event(struct pd_port *pd_port, uint8_t notify);
int pd_send_vdm_discover_id(struct pd_port *pd_port, uint8_t sop_type);
int pd_send_vdm_discover_svids(struct pd_port *pd_port, uint8_t sop_type);
int pd_send_vdm_discover_modes(struct pd_port *pd_port, uint8_t sop_type, uint16_t svid);
int pd_send_vdm_enter_mode(struct pd_port *pd_port,uint8_t sop_type, uint16_t svid, uint8_t obj_pos);
int pd_send_vdm_exit_mode(struct pd_port *pd_port, uint8_t sop_type, uint16_t svid, uint8_t obj_pos);
int pd_send_vdm_attention(struct pd_port *pd_port,uint8_t sop_type, uint16_t svid, uint8_t obj_pos);
int pd_send_vdm_dp_attention(struct pd_port *pd_port,uint8_t sop_type, uint8_t obj_pos, uint32_t dp_status);
int pd_send_vdm_dp_status(struct pd_port *pd_port, uint8_t sop_type, uint8_t obj_pos, uint8_t cnt, uint32_t *data_obj);
int pd_send_vdm_dp_config(struct pd_port *pd_port, uint8_t sop_type, uint8_t obj_pos, uint8_t cnt, uint32_t *data_obj);
int pd_reply_svdm_request_simply(struct pd_port *pd_port, uint8_t reply);
int pd_reply_wait_reject_msg(struct pd_port *pd_port);
int pd_reply_wait_reject_msg_no_resp(struct pd_port *pd_port);
bool pd_put_pe_event(struct pd_port *pd_port, uint8_t pe_event);
void pd_handle_first_pd_command(struct pd_port *pd_port);
int pd_handle_soft_reset(struct pd_port *pd_port);
int pd_init_message_hdr(struct pd_port *pd_port, bool act_as_sink);
int pd_update_connect_state(struct pd_port *pd_port, uint8_t state);
bool pd_is_cable_communication_available(struct pd_port *pd_port);
void pd_set_sink_tx(struct pd_port *pd_port, uint8_t cc);
void pd_sync_sop_spec_revision(struct pd_port *pd_port);
void pd_sync_sop_prime_spec_revision(struct pd_port *pd_port, uint8_t rev);
void pd_sync_svdm_ver_min(struct pd_port *pd_port, enum tcpm_transmit_type sop_type, uint8_t ver);
bool pd_is_multi_chunk_msg(struct pd_port *pd_port);
void pd_free_unexpected_event(struct pd_port *pd_port);
int pd_reset_protocol_layer(struct pd_port *pd_port, bool sop_only);
int pd_set_rx_enable(struct pd_port *pd_port, uint8_t enable);
int pd_enable_vbus_valid_detection(struct pd_port *pd_port, bool wait_valid);
int pd_enable_vbus_safe0v_detection(struct pd_port *pd_port);
int pd_enable_vbus_stable_detection(struct pd_port *pd_port);
uint32_t pd_reset_pdo_power(struct sgm41620_tcpc *tcpc, uint32_t pdo, uint32_t imax);
void pd_extract_rdo_power(uint32_t rdo, uint32_t pdo, uint32_t *op_curr, uint32_t *max_curr);
int pd_send_soft_reset(struct pd_port *pd_port);
int pd_send_cable_soft_reset(struct pd_port *pd_port);
int pd_send_hard_reset(struct pd_port *pd_port);
int pd_send_bist_mode2(struct pd_port *pd_port);
int pd_disable_bist_mode2(struct pd_port *pd_port);
void pd_handle_hard_reset_recovery(struct pd_port *pd_port);
/* ---- Send / Reply SVDM Command ----*/
uint8_t pd_get_svdm_ver_min(struct pd_port *pd_port, enum tcpm_transmit_type sop_type);
/* Auto enable timer if success */
int pd_send_svdm_request(struct pd_port *pd_port,
	uint8_t sop_type, uint16_t svid, uint8_t vdm_cmd,
	uint8_t obj_pos, uint8_t cnt, uint32_t *data_obj,
	uint32_t timer_id);
int pd_reply_svdm_request(struct pd_port *pd_port,uint8_t reply, uint8_t cnt, uint32_t *data_obj);
int pd_set_data_role(struct pd_port *pd_port, uint8_t dr);
int pd_set_power_role(struct pd_port *pd_port, uint8_t pr);
/* ---- PD notify TCPC Policy Engine State Changed ---- */
void pd_try_put_pe_idle_event(struct pd_port *pd_port);
void pd_notify_pe_idle(struct pd_port *pd_port);
void pd_notify_pe_send_hard_reset(struct pd_port *pd_port);
void pd_notify_pe_execute_pr_swap(struct pd_port *pd_port);
void pd_notify_pe_hard_reset_completed(struct pd_port *pd_port);
int pd_reset_local_hw(struct pd_port *pd_port);
int pd_set_vconn(struct pd_port *pd_port, uint8_t role);
int pd_enable_bist_test_mode(struct pd_port *pd_port, bool en);
void pd_notify_pe_transit_to_default(struct pd_port *pd_port);
bool pd_is_pe_wait_pd_transmit_done(struct pd_port *pd_port);
void pd_notify_pe_transmit_msg(struct pd_port *pd_port, uint8_t type);
void pd_notify_tcp_event_buf_reset(struct pd_port *pd_port, uint8_t reason);
void pd_notify_tcp_event_1st_result(struct pd_port *pd_port, int ret);
void pd_notify_tcp_event_2nd_result(struct pd_port *pd_port, int ret);
void pd_notify_tcp_vdm_event_2nd_result(struct pd_port *pd_port, uint8_t ret);
void pe_data_init(struct pe_data *pe_data);
void pd_notify_pe_error_recovery(struct pd_port *pd_port);
void pd_notify_pe_pr_changed(struct pd_port *pd_port);
void pd_noitfy_pe_bist_mode(struct pd_port *pd_port, uint8_t mode);
void pd_notify_pe_reset_protocol(struct pd_port *pd_port);
void pd_notify_pe_cancel_pr_swap(struct pd_port *pd_port);
void pd_reset_pe_timer(struct pd_port *pd_port);
uint32_t pd_get_cable_current_limit(struct pd_port *pd_port);
/* ---- Send PD Message ----*/
int pd_send_message(uint8_t sop_type,uint8_t msg, bool ext, uint16_t count, const uint32_t *data);
int pd_send_ext_msg(struct pd_port *pd_port,
	uint8_t sop_type, uint8_t msg, bool request,
	uint8_t chunk_nr, uint8_t size, const uint8_t *data);
int pd_send_sop_ext_msg(struct pd_port *pd_port, uint8_t msg, uint8_t size, const void *data);
struct pd_battery_info *pd_get_battery_info(struct pd_port *pd_port, enum pd_battery_reference ref);
int pd_send_sop_ctrl_msg(uint8_t msg);
int pd_send_sop_prime_ctrl_msg(uint8_t msg);
int pd_send_sop_prime_prime_ctrl_msg(uint8_t msg);
int pd_send_data_msg(uint8_t sop_type, uint8_t msg, uint8_t cnt, uint32_t *payload);
int pd_send_sop_data_msg(uint8_t msg, uint8_t cnt, const uint32_t *payload);
void pd_restart_timer(struct pd_port *pd_port, uint32_t timer_id);
void pd_enable_timer(struct pd_port *pd_port, uint32_t timer_id);
void pd_enable_pe_state_timer(struct pd_port *pd_port, uint32_t timer_id);
void pd_disable_timer(struct pd_port *pd_port, uint32_t timer_id);
void pd_disable_pe_state_timer(struct pd_port *pd_port);
int pd_core_init(void);
bool pd_is_reset_cable(struct pd_port *pd_port);
void pd_reset_svid_data(struct pd_port *pd_port);

static inline bool pd_curr_is_vdm_evt(struct pd_port *pd_port)
{
    return pd_port->curr_is_vdm_evt;
}
static inline struct pd_event *pd_get_curr_pd_event(struct pd_port *pd_port)
{
    return &pd_port->curr_pd_event;
}

static inline uint32_t pd_get_msg_vdm_hdr(struct pd_port *pd_port)
{
    return pd_port->curr_vdm_hdr;
}

static inline struct dp_data *pd_get_dp_data(struct pd_port *pd_port)
{
    return &pd_port->pe_data.dp_data;
}

static inline void *pd_get_msg_data_payload(struct pd_port *pd_port)
{
    return pd_port->pd_msg_data_payload;
}

static inline uint32_t *pd_get_msg_vdm_data_payload(struct pd_port *pd_port)
{
    uint32_t *payload = (uint32_t *) pd_port->pd_msg_data_payload;

    if (payload == NULL)
        return NULL;

    return payload+1;
}

static inline uint8_t pd_get_msg_data_count(struct pd_port *pd_port)
{
    return pd_port->pd_msg_data_count;
}

static inline uint8_t pd_get_msg_vdm_data_count(struct pd_port *pd_port)
{
    return pd_port->pd_msg_data_count-1;
}

static inline uint16_t pd_get_msg_data_size(struct pd_port *pd_port)
{
	return pd_port->pd_msg_data_size;
}

#if CONFIG_USB_PD_REV30
static inline uint8_t pd_get_msg_hdr_ext(struct pd_port *pd_port)
{
	return PD_HEADER_EXT(pd_port->curr_msg_hdr);
}
#endif	/* CONFIG_USB_PD_REV30 */

static inline uint8_t pd_get_msg_hdr_rev(struct pd_port *pd_port)
{
	return PD_HEADER_REV(pd_port->curr_msg_hdr);
}

static inline uint8_t pd_get_msg_hdr_cnt(struct pd_port *pd_port)
{
	return PD_HEADER_CNT(pd_port->curr_msg_hdr);
}

static inline uint8_t pd_get_msg_hdr_id(struct pd_port *pd_port)
{
	return PD_HEADER_ID(pd_port->curr_msg_hdr);
}

static inline bool pd_is_cable_communication_available(struct pd_port *pd_port)
{
	return !!pd_port->vconn_role;
}

static inline bool pd_is_discover_cable(struct pd_port *pd_port)
{
	if (pd_port->pe_data.discover_id_counter >= PD_DISCOVER_ID_COUNT)
		return false;

	return pd_is_cable_communication_available(pd_port);
}

static inline int pd_is_source_support_apdo(struct pd_port *pd_port)
{
#if CONFIG_USB_PD_REV30_PPS_SINK
	uint8_t i;
	struct pd_port_power_caps *src_cap = &pd_port->pe_data.remote_src_cap;

	/* index0 always be fixed 5V */
	for (i = 1; i < src_cap->nr; i++) {
		if (PDO_TYPE(src_cap->pdos[i]) == PDO_TYPE_APDO)
			return true;
	}
#endif	/* CONFIG_USB_PD_REV30_PPS_SINK */

	return false;
}

#endif /* PD_CORE_H_ */

